/*
 * Copyright 2002-2016 the atnoce.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.atnoce.onepass.net;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atnoce.onepass.core.SecurityController;
import com.atnoce.onepass.dao.DirTypeDao;
import com.atnoce.onepass.dao.OnepassConfigDao;
import com.atnoce.onepass.dao.PasswordItemDao;
import com.atnoce.onepass.pojo.*;
import com.atnoce.onepass.utils.Cache;
import com.atnoce.onepass.utils.Const;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.*;

/**
 * @author atnoce.com
 * @date 2016/11/4
 * @since 1.0.0
 */
public class BasicNetService {
    private static BasicNetService service;
    OnepassConfigDao onepassConfigDao;
    DirTypeDao typeDao;
    PasswordItemDao passwordItemDao;
    public static long getTime() throws MalformedURLException, IOException {
        //TimeZone.setDefault(TimeZone.getTimeZone("GMT+8")); // 时区设置
        String proConfig = Cache.getProConfig(Const.TIMESERVER);
        if (proConfig==null){
            proConfig="http://www.360.com";
        }else{
            proConfig="http://"+proConfig;
        }
        URL url=new URL(proConfig);//取得资源对象
        URLConnection uc=url.openConnection();//生成连接对象
        uc.connect(); //发出连接
        long ld=uc.getDate(); //取得网站日期时间（时间戳）
        return ld;
    }
    /**
     * 获取网络服务实例
     * @return
     */
    public static BasicNetService getInstance(){
        if(service==null){
            service=new BasicNetService();
        }
        return service;
    }
    public Map<String,Object> regCheckColudAccount(String account) throws Exception {
        Map<String,Object> map=new HashMap<>();
        boolean flag=false;
        String msg="出错了";
        HttpPost httpPost=new HttpPost("http://"+Cache.getProConfig(Const.BASE_SERVER_ADDR)+"/onepass/colud/reg.mvc");
        List<BasicNameValuePair> nvps=new ArrayList<>();
        nvps.add(new BasicNameValuePair("regAccount",account));
        nvps.add(new BasicNameValuePair("regType","pc-window7-64bit"));
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        CloseableHttpClient httpClient= HttpClients.createDefault();
        RequestConfig requestConfig=RequestConfig.custom().setConnectionRequestTimeout(5000).setConnectTimeout(5000).setSocketTimeout(5000).build();
        httpPost.setConfig(requestConfig);
        try {
            CloseableHttpResponse execute = httpClient.execute(httpPost);
            if (execute.getStatusLine().getStatusCode() == 200) {
                String s1 = EntityUtils.toString(execute.getEntity());
                if (StringUtils.equals("true",s1)){
                    flag=true;
                }else{
                    flag=false;
                    msg=s1;

                }
            }
        }catch (Exception e){
            flag=false;
            msg=e.getMessage();
            e.printStackTrace();
        }finally {
            map.put("flag",flag);
            map.put("msg",msg);
        }
        return map;
    }
    public  Map<String,Object> exeSynch(String coludAccound) throws NoSuchAlgorithmException, Exception{
        if (onepassConfigDao==null)onepassConfigDao=new OnepassConfigDao();
        if (typeDao==null)typeDao=new DirTypeDao();
        if (passwordItemDao==null)passwordItemDao=new PasswordItemDao();
        Map<String,Object> result=new HashMap<>();

        /**
         * 同步分三步，
         *  1、同步配置表
         *  2、同步分类表
         *  3、同步密码项表
         */
        //同步配置
        SynchHead sh=new SynchHead();
        //sh.setAccount(SecurityController.getSecurityInstence().decryptColudAccount(Cache.getProConfig(Const.COLUDACCOUNT),Cache.getKey()));
        sh.setAccount(coludAccound);
        sh.setObjType("config");
        sh.getContent().add(Cache.getOc());
        String s = JSON.toJSONString(sh);
        Map<String, Object> configResult = synchHead(s);
        if((boolean)configResult.get("flag")){
            String ret= (String) configResult.get("ret");
            //处理分类同步结果
            configSyncHandle(ret,onepassConfigDao);
        }else{
            throw new Exception((String)configResult.get("msg"));
        }
        //同步分类
        SynchHead dirSh=new SynchHead();
        dirSh.setObjType("dir");
        dirSh.setAccount(coludAccound);
        //获取所有分类
        List<DirTypeSync> syncDirTypes = typeDao.getSyncDirTypes();
        dirSh.getContent().addAll(syncDirTypes);
        Map<String, Object> dirResult = synchHead(JSON.toJSONString(dirSh));
        if ((boolean)dirResult.get("flag")){
            String ret= (String) dirResult.get("ret");
            dirSyncHandle(ret,typeDao);
        }else{
            throw new Exception((String)configResult.get("msg"));
        }

        //同步密码项
        SynchHead itemSh=new SynchHead();
        itemSh.setObjType("item");
        itemSh.setAccount(coludAccound);
        List<PasswordItemSync> syncPasswordItem = passwordItemDao.getSyncPasswordItem();
        itemSh.getContent().addAll(syncPasswordItem);
        Map<String, Object> itemResult = synchHead(JSON.toJSONString(itemSh));
        if ((boolean)itemResult.get("flag")){
            String ret= (String) itemResult.get("ret");
            passitemSyncHandle(ret,passwordItemDao);
        }else{
            throw new Exception((String)configResult.get("msg"));
        }
        return result;
    }

    private void configSyncHandle(String json,OnepassConfigDao configDao) throws SQLException, ClassNotFoundException {
        SyncResult syncResult = JSON.parseObject(json, SyncResult.class);
        if (syncResult.isUpdate()){
            List updateContent = syncResult.getUpdateContent();
            if (updateContent!=null&&updateContent.size()>0){
                JSONObject o = (JSONObject)updateContent.get(0);
                OnepassConfig onepassConfig = JSON.toJavaObject(o, OnepassConfig.class);
                configDao.updateConfig(onepassConfig);
            }
        }
        if (syncResult.isInsert()){
            List insertContent = syncResult.getInsertContent();
            if (insertContent!=null&&insertContent.size()>0){
                JSONObject o = (JSONObject)insertContent.get(0);
                OnepassConfig onepassConfig = JSON.toJavaObject(o, OnepassConfig.class);
                configDao.insertConfig(onepassConfig);
            }
        }
    }
    private void passitemSyncHandle(String json,PasswordItemDao itemDao) throws SQLException, ClassNotFoundException {
        SyncResult syncResult = JSON.parseObject(json, SyncResult.class);
        if (syncResult.isUpdate()){
            List updateContent = syncResult.getUpdateContent();
            if (updateContent!=null&&updateContent.size()>0){
                for (Object o:updateContent){
                    PasswordItem passwordItem = JSON.toJavaObject((JSONObject) o, PasswordItem.class);
                    itemDao.updatePasswordItemFromId(passwordItem);
                }
            }
        }
        if (syncResult.isInsert()){
            List insertContent = syncResult.getInsertContent();
            if (insertContent!=null&&insertContent.size()>0){
                for (Object o:insertContent){
                    PasswordItem passwordItem = JSON.toJavaObject((JSONObject) o, PasswordItem.class);
                    itemDao.addPasswordItem(passwordItem);
                }
            }
        }
    }
    private void dirSyncHandle(String json,DirTypeDao typeDao) throws SQLException, ClassNotFoundException {
        SyncResult syncResult = JSON.parseObject(json, SyncResult.class);
        //判断有没有需要更新的
        if(syncResult.isUpdate()){
            List updateContent = syncResult.getUpdateContent();
            for (Object jo:updateContent){
                DirType dirType = JSON.toJavaObject((JSONObject) jo, DirType.class);
                typeDao.updateDirType(dirType);
            }
        }
        //判断有没有插入的
        if (syncResult.isInsert()){
            List insertContent = syncResult.getInsertContent();
            for (Object io:insertContent){
                DirType dirType = JSON.toJavaObject((JSONObject) io, DirType.class);
                typeDao.addDirType(dirType);
            }
        }
    }

    private Map<String,Object> synchHead(String json) throws IOException ,Exception{
        Map<String,Object> map=new HashMap<>();
        map.put("flag",false);
        map.put("msg","发生问题");
        HttpPost httpPost=new HttpPost("http://"+Cache.getProConfig(Const.BASE_SERVER_ADDR)+"/onepass/synch/syncHend.mvc");
        List<BasicNameValuePair> nvps=new ArrayList<>();
        nvps.add(new BasicNameValuePair("data",json));
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        CloseableHttpClient httpClient= HttpClients.createDefault();
       // httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,10000);
        try{
            CloseableHttpResponse execute = httpClient.execute(httpPost);
            if(execute.getStatusLine().getStatusCode()==200){
                String s1 = EntityUtils.toString(execute.getEntity());
                /*InputStream content = execute.getEntity().getContent();
                byte[] bytes=new byte[Integer.parseInt(execute.getEntity().getContentLength()+"")];
                content.read(bytes);
                String s=new String(bytes,"utf-8");*/
                JSONObject jsonObject = JSON.parseObject(s1);
                boolean flag = jsonObject.getBoolean("flag");
                if (flag){
                    map.put("flag", true);
                    map.put("ret",s1);
                }else{
                    map.put("flag", false);
                    map.put("msg", jsonObject.getString("msg"));
                }
            }else{
                map.put("flag", false);
                map.put("msg", "请求服务器失败!错误代码："+execute.getStatusLine().getStatusCode());
            }
            try{
                EntityUtils.consume(execute.getEntity());
            }finally {
                execute.close();
            }
        }catch (HttpHostConnectException e){
            throw new Exception("无法连接服务器！");
        }catch (IOException e){
            throw new IOException("解析服务器数据发生错误！");
        }catch (Exception e){
            throw new Exception("同步数据发生问题！");
        }
        return map;
    }
    public Map<String, Object> bindColudAccount(String account) throws Exception {
        Map<String,Object> map=new HashMap<>();
        map.put("flag",false);
        map.put("msg","发生问题");
        HttpPost httpPost=new HttpPost("http://"+Cache.getProConfig(Const.BASE_SERVER_ADDR)+"/onepass/colud/bindColudAccount.mvc");
        List<BasicNameValuePair> nvps=new ArrayList<>();
        nvps.add(new BasicNameValuePair("coludAccount",account));
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        CloseableHttpClient httpClient= HttpClients.createDefault();
        try{
            CloseableHttpResponse execute = httpClient.execute(httpPost);
            if(execute.getStatusLine().getStatusCode()==200){
                String s = EntityUtils.toString(execute.getEntity());
                if(StringUtils.equals(s,"true")){
                    map.put("flag",true);
                }else{
                    map.put("flag",false);
                    map.put("msg",s);
                }
            }else{
                map.put("flag", false);
                map.put("msg", "请求服务器失败!错误代码："+execute.getStatusLine().getStatusCode());
            }
            try{
                EntityUtils.consume(execute.getEntity());
            }finally {
                execute.close();
            }
        }catch (HttpHostConnectException e){
            throw new Exception("无法连接服务器！");
        }catch (IOException e){
            throw new IOException("解析服务器数据发生错误！");
        }catch (Exception e){
            throw new Exception("与服务器通信发生问题！");
        }
        return map;
    }
    public Map<String, Object> testNetHandler(String address){
        Map<String,Object> map=new HashMap<>();
        map.put("flag",false);
        map.put("msg","发生问题");
        HttpPost httpPost=new HttpPost("http://"+address);
        CloseableHttpClient httpClient= HttpClients.createDefault();
        try{
            CloseableHttpResponse execute = httpClient.execute(httpPost);
            if(execute.getStatusLine().getStatusCode()==200){
               map.put("flag",true);
            }else{
                map.put("flag", false);
                map.put("msg", "请求服务器失败!错误代码："+execute.getStatusLine().getStatusCode());
            }
            try{
                EntityUtils.consume(execute.getEntity());
            }finally {
                execute.close();
            }
        }catch (HttpHostConnectException e){
            map.put("flag",false);
            map.put("msg","无法连接服务器！"+e.getMessage());
        }catch (IOException e){
            map.put("flag",false);
            map.put("msg","解析服务器数据发生错误！"+e.getMessage());
        }catch (Exception e){
            map.put("flag",false);
            map.put("msg","与服务器通信发生问题！"+e.getMessage());
        }
        return map;
    }



    /**
     * 测试并设置授时服务器
     * @param addr
     */
    public Map<String, Object> testAndSetTimerServer(String addr) {
        Map<String,Object> map=new HashMap<>();
       boolean flag=false;
        String msg="";
        map.put("msg","发生问题");
        //TimeZone.setDefault(TimeZone.getTimeZone("GMT+8")); // 时区设置

        URL url= null;//取得资源对象
        try {
            url = new URL(addr);
            URLConnection uc;
            List<Long> wucha=new ArrayList<>();
            for (int a=0;a<5;a++){
                uc=url.openConnection();//生成连接对象
                uc.connect(); //发出连接
                long ld=uc.getDate(); //取得网站日期时间（时间戳）
                long localTime = System.currentTimeMillis();
                wucha.add(Math.abs(ld-localTime));
                Thread.sleep(1000);
            }
            long endL=0;
            for (Long l:wucha){
                endL+=l;
            }
            if (endL/wucha.size()<5000){
                flag=true;
            }else{
                flag=false;
                msg="授时服务器延迟超过最大允许值，请更换授时服务器地址！";
            }
        } catch (MalformedURLException e) {
            flag=false;
            msg=e.getMessage();
            e.printStackTrace();
        } catch (IOException e) {
            flag=false;
            msg=e.getMessage();
            e.printStackTrace();
        } catch (InterruptedException e) {
            flag=false;
            msg=e.getMessage();
            e.printStackTrace();
        }finally {
            map.put("flag",flag);
            map.put("msg",msg);
            return map;
        }

    }
}
